/**
 * @file       bsp_ebcoder.cpp
 * @author     MatCoreShu (2874567545@qq.com)
 * @date       2025-05-22
 * @version    1.0
 * @note       模块状态：OK
 * @copyright  Copyright (c) 2025  [ zhangshuoshi ]
 * @API说明     (API Documentation)
 * ==============================================
 * ==============================================
 */
#include "bsp_encoder.h"
#include "convert.h"
#include "bsp_pthread.h"
#include "bsp_uart.h"

// 智能码率 算法步长
static RK_S32 aq_thd_smart[16] = {
    1,  3,  3,  3,  3,  3,  5,  5,
    8,  8,  8, 15, 15, 20, 25, 28
};

static RK_S32 aq_step_smart[16] = {
    -8, -7, -6, -5, -4, -3, -2, -1,
    0,  1,  2,  3,  4,  6,  8, 10
};
// 传统算法 aq步长
static RK_S32 aq_thd[16] = {
    0,  0,  0,  0,
    3,  3,  5,  5,
    8,  8,  8,  15,
    15, 20, 25, 25
};

static RK_S32 aq_step_i_ipc[16] = {
    -8, -7, -6, -5,
    -4, -3, -2, -1,
    0,  1,  2,  3,
    5,  7,  7,  8,
};

static RK_S32 aq_step_p_ipc[16] = {
    -8, -7, -6, -5,
    -4, -2, -1, -1,
    0,  2,  3,  4,
    6,  8,  9,  10,
};

//1初始化mpp编码器参数
MPP_Encoder* Mpp_encoder_init(int width, int height, int fps, int usb_devnum,MppFrameFormat args_fmt)
{
    printf("-------Mpp_encoder_init-------\n");
    MPP_RET ret = MPP_OK;
    MPP_Encoder* mppenc = (MPP_Encoder *)malloc(sizeof(MPP_Encoder)); //开辟一个结构体变量用方便承接更新的变量参数
    if (mppenc == nullptr)
    {
        perror("Cannot allocate memory for structure MPP_Encoder");
        return nullptr;
    }
    memset(mppenc, 0, sizeof(MPP_Encoder));

    /*获取结构体体传过来的参数
    可见：640*480 1920*1080
    红外：640*480（这个是转化后的）
    */
   if (usb_devnum == 0)
    {
        /* 控制底层的格式单独配置
        vheigrh
        vwidth
        vfmt
        */
        //转码前数据格式设置
        mppenc->vwidth      = 640;
        mppenc->vheight     = 512;
        mppenc->vfmt        = MPP_FMT_YUV400;
        //转码后数据格式设置 从结构体传参获取
        mppenc->width       = width;
        mppenc->height      = height;
        mppenc->usbfmt      = args_fmt; //MPP_FMT_YUV420SP
    }
    else{
        mppenc->width       = width;
        mppenc->height      = height;
        mppenc->usbfmt      = args_fmt;

    }
printf("mppenc: w = [%d], h = [%d]\n",mppenc->width ,mppenc->height );
    mppenc->type        = MPP_VIDEO_CodingHEVC;
    mppenc->rc_mode     = MPP_ENC_RC_MODE_CBR;
    mppenc->hor_stride  = mpi_enc_width_default_stride(width, mppenc->usbfmt);
    mppenc->ver_stride  = MPP_ALIGN(height, 2);
printf("------hor_stride %d, ver_stride = %d------\n",mppenc->hor_stride,mppenc->ver_stride);
    mppenc->fps_in_num  = fps;
    mppenc->fps_in_flex = 0;
    mppenc->fps_in_den  = 1;
    mppenc->fps_out_num = fps;
    mppenc->fps_out_flex= 0;
    mppenc->fps_out_den = 1;
    mppenc->bps         = width * height / 8 *(mppenc->fps_out_num/mppenc->fps_out_den);
    mppenc->bps_max     = mppenc->bps * 17 / 16;
    mppenc->bps_min     = mppenc->bps * 15 / 16;
    mppenc->timeout     = MPP_POLL_BLOCK;
    mppenc->usingnum    = usb_devnum;
    mppenc->cam_frm_idx = -1;
    RockchipSocType soc_type = mpp_get_soc_type();
    if (soc_type == ROCKCHIP_SOC_RK3588)
    {
        RK_U32 w = MPP_ALIGN(width, 16);
        RK_U32 h = MPP_ALIGN(width, 16);
        mppenc->mdinfo_size = (MPP_ALIGN( w, 64) >> 6) * (MPP_ALIGN( h, 64) >> 6) * 32;
    } else {
        RK_U32 w = MPP_ALIGN(width, 16);
        RK_U32 h = MPP_ALIGN(width, 16);
        mppenc->mdinfo_size = (MPP_VIDEO_CodingHEVC == mppenc->type) ? 
                    (MPP_ALIGN( w, 32) >> 6) * (MPP_ALIGN( h, 32) >> 5) * 32:
                    (MPP_ALIGN( w, 64) >> 6) * (MPP_ALIGN( h, 16) >> 4) * 32;
    }

    mppenc->usbname = (char *)malloc(64);
    if (mppenc->usbname == nullptr)
    {
        perror("Cannot allocate memory for mppenc->usbname");
        return NULL;
    }
    
    snprintf(mppenc->usbname, 64, "/dev/video%d", usb_devnum);
printf("[%s]\n",mppenc->usbname);
    if (usb_devnum == 0)
    {
        mppenc->usbcam_ctx  = camera_source_init(mppenc->usbname, 4, mppenc->vwidth , mppenc->vheight, mppenc->vfmt);
    }
    else{
        mppenc->usbcam_ctx  = camera_source_init(mppenc->usbname, 4, width, height, mppenc->usbfmt);
    }
    if (mppenc->usbcam_ctx == nullptr)
    {
        perror("Cannot open usbcam");
        return NULL;
    }
    if (mppenc->usbcam_ctx != nullptr)
    {
        char *buf = (char *)malloc(64);
        if (mppenc->type == MPP_VIDEO_CodingHEVC)
        {
            snprintf(buf, 64, "envideo%d.h265", usb_devnum);
        }
        else if (mppenc->type == MPP_VIDEO_CodingAVC)
        {
            snprintf(buf, 64, "envideo%d.h264", usb_devnum);
        }  
        else{
            snprintf(buf, 64, "en_other_video%d.h264", usb_devnum);
        }
        printf("[%s]\n",buf);
        mppenc->fp_output = fopen(buf, "w+b");
        if (NULL == mppenc->fp_output) {
            mpp_err("failed to open output file %s\n", mppenc->file_output);
        }   
    }

    // update resource parameter
    switch (mppenc->usbfmt & MPP_FRAME_FMT_MASK) {
        case MPP_FMT_YUV420SP:
        case MPP_FMT_YUV420P: {
            mppenc->frame_size = MPP_ALIGN(mppenc->hor_stride, 64) * MPP_ALIGN(mppenc->ver_stride, 64) * 3 / 2;
        } break;

        case MPP_FMT_YUV422_YUYV :
        case MPP_FMT_YUV422_YVYU :
        case MPP_FMT_YUV422_UYVY :
        case MPP_FMT_YUV422_VYUY :
        case MPP_FMT_YUV422P :
        case MPP_FMT_YUV422SP : {
            mppenc->frame_size = MPP_ALIGN(mppenc->hor_stride, 64) * MPP_ALIGN(mppenc->ver_stride, 64) * 2;
        } break;
        case MPP_FMT_YUV400 :
        case MPP_FMT_RGB444 :
        case MPP_FMT_BGR444 :
        case MPP_FMT_RGB555 :
        case MPP_FMT_BGR555 :
        case MPP_FMT_RGB565 :
        case MPP_FMT_BGR565 :
        case MPP_FMT_RGB888 :
        case MPP_FMT_BGR888 :
        case MPP_FMT_RGB101010 :
        case MPP_FMT_BGR101010 :
        case MPP_FMT_ARGB8888 :
        case MPP_FMT_ABGR8888 :
        case MPP_FMT_BGRA8888 :
        case MPP_FMT_RGBA8888 : {
            mppenc->frame_size = MPP_ALIGN(mppenc->hor_stride, 64) * MPP_ALIGN(mppenc->ver_stride, 64);
        } break;

        default: {
            mppenc->frame_size = MPP_ALIGN(mppenc->hor_stride, 64) * MPP_ALIGN(mppenc->ver_stride, 64) * 3/2;
            // printf("MPP_ALIGN(mppenc->hor_stride, 64) = [%d],MPP_ALIGN(mppenc->ver_stride, 64) = [%d]",MPP_ALIGN(mppenc->hor_stride, 64),MPP_ALIGN(mppenc->ver_stride, 64));
        } break;
    }

    if (MPP_FRAME_FMT_IS_FBC(mppenc->usbfmt))
    {
        mppenc->header_size = MPP_ALIGN(MPP_ALIGN(mppenc->width, 16) * MPP_ALIGN(mppenc->height, 16) / 16, SZ_4K);
    }
    else{
        mppenc->header_size = 0;
    }
    /*qc等参数*/ 
    if (mppenc->rc_mode == MPP_ENC_RC_MODE_FIXQP) {
        if (mppenc->type == MPP_VIDEO_CodingAVC ||
            mppenc->type == MPP_VIDEO_CodingHEVC)
            mppenc->qp_init = 26;
    }
printf("-------Mpp_encoder_init-------\n");
    return mppenc;
}
MPP_RET Mpp_encoder_deinit(MPP_Encoder* mppenc)
{
    if (mppenc == nullptr)
    {
        return MPP_OK;
    }
    
    if (mppenc) {
        if (mppenc->usbcam_ctx != nullptr) {
            camera_source_deinit(mppenc->usbcam_ctx);
            mppenc->usbcam_ctx = nullptr;
        }
        // if (mppenc->fp_input) {
        //     fclose(mppenc->fp_input);
        //     mppenc->fp_input = NULL;
        // }
        if (mppenc->usbname != nullptr) {
            free(mppenc->usbname);
            mppenc->usbname = nullptr;
        }

        if (mppenc->fp_output != nullptr) {
            fclose(mppenc->fp_output);
            mppenc->fp_output = nullptr;
        }

        free(mppenc);
    }
    return MPP_OK;
}

static MPP_RET mpp_enc_cfg_setup(MPP_Encoder *mppenc)
{
    MPP_RET ret;
    MppEncCfg cfg = mppenc->cfg;

    RK_U32 rotation;
    RK_U32 mirroring;
    RK_U32 flip;

    //     //控制I帧和P帧的 自适应量化阈值
    // mpp_enc_cfg_set_st(cfg, "hw:aq_thrd_i", aq_thd);
    // mpp_enc_cfg_set_st(cfg, "hw:aq_thrd_p", aq_thd);
    // mpp_enc_cfg_set_st(cfg, "hw:aq_step_i", aq_step_i_ipc);
    // mpp_enc_cfg_set_st(cfg, "hw:aq_step_p", aq_step_p_ipc);
    // // QP(real) = qbias_en - (qbias_i/qbias_p)  控制质量开关
    // mpp_enc_cfg_set_s32(cfg, "hw:qbias_en", 1);
    // mpp_enc_cfg_set_s32(cfg, "hw:qbias_i", 0); //-5～+10
    // mpp_enc_cfg_set_s32(cfg, "hw:qbias_p", 0); //-5～+10
    // //调整运动估计
    // mpp_enc_cfg_set_s32(cfg, "hw:skip_bias_en", 0);
    // mpp_enc_cfg_set_s32(cfg, "hw:skip_bias", 4);
    // mpp_enc_cfg_set_s32(cfg, "hw:skip_sad", 8);

    // mpp_enc_cfg_set_s32(cfg, "rc:cu_qp_delta_depth", 2);
    // mpp_enc_cfg_set_s32(cfg, "rc:fqp_min_i",10);
    // mpp_enc_cfg_set_s32(cfg, "rc:fqp_max_i",45);
    // mpp_enc_cfg_set_s32(cfg, "rc:fqp_min_p",10);
    // mpp_enc_cfg_set_s32(cfg, "rc:fqp_max_p",45);
    // 抗闪烁
    // // 强度等级：1（轻度）→ 3（强力）
    // mpp_enc_cfg_set_s32(cfg, "tune:anti_flicker_str", 0); 

    // // 开启 滤波 1 open 0 off
    // mpp_enc_cfg_set_s32(cfg, "tune:atl_str", 1); 
    // // 0 off ; 1 2 3
    // // I 帧高强度，P 帧中等强度
    // mpp_enc_cfg_set_s32(cfg, "tune:atr_str_i", 3);
    // mpp_enc_cfg_set_s32(cfg, "tune:atr_str_p", 2);
    // // I 帧全强度，P 帧基础强度
    // mpp_enc_cfg_set_s32(cfg, "tune:sao_str_i", 3);
    // mpp_enc_cfg_set_s32(cfg, "tune:sao_str_p", 2);
    // mpp_enc_cfg_set_s32(cfg, "tune:scene_mode", 1);//0 平衡 1低延迟 ipc
    // //去模糊
    // //deblur_en去模糊功能总开关0: 关闭, 1: 开启	
    // //deblur_str去模糊强度与实现方案0-3: 软硬协同, 4-7: 纯硬件加速	
    // mpp_enc_cfg_set_s32(cfg, "tune:deblur_en",0 );
    // mpp_enc_cfg_set_s32(cfg, "tune:deblur_str", 0);

    // //mpp_enc_cfg_set_s32(ctx->cfg, "tune:rc_container", 0); //2 强控制模式下建议使用 CBR  1 若控制使用VBR 和 动态QP
    // mpp_enc_cfg_set_s32(cfg, "tune:vmaf_opt", 0);


    mpp_enc_cfg_set_s32(cfg, "prep:width", mppenc->width);
    mpp_enc_cfg_set_s32(cfg, "prep:height", mppenc->height);
    mpp_enc_cfg_set_s32(cfg, "prep:hor_stride", mppenc->hor_stride);
    mpp_enc_cfg_set_s32(cfg, "prep:ver_stride", mppenc->ver_stride);
    printf("hor_stride = [%d],ver_stride = [%d]\n",mppenc->hor_stride,mppenc->ver_stride);
    mpp_enc_cfg_set_s32(cfg, "prep:format", mppenc->usbfmt);
    mpp_enc_cfg_set_s32(cfg, "rc:mode", mppenc->rc_mode);
    // mpp_enc_cfg_set_u32(cfg, "rc:max_reenc_times", 0);
    // mpp_enc_cfg_set_u32(cfg, "rc:super_mode", 0);
    /* fix input / output frame rate */
    mpp_enc_cfg_set_s32(cfg, "rc:fps_in_flex", mppenc->fps_in_flex);
    mpp_enc_cfg_set_s32(cfg, "rc:fps_in_num", mppenc->fps_in_num);
    mpp_enc_cfg_set_s32(cfg, "rc:fps_in_denom", mppenc->fps_in_den);
    mpp_enc_cfg_set_s32(cfg, "rc:fps_out_flex", mppenc->fps_out_flex);
    mpp_enc_cfg_set_s32(cfg, "rc:fps_out_num", mppenc->fps_out_num);
    mpp_enc_cfg_set_s32(cfg, "rc:fps_out_denom", mppenc->fps_out_den);

    /* drop frame or not when bitrate overflow */
    mpp_enc_cfg_set_u32(cfg, "rc:drop_mode", MPP_ENC_RC_DROP_FRM_DISABLED);
    mpp_enc_cfg_set_u32(cfg, "rc:drop_thd", 20);        /* 20% of max bps */
    mpp_enc_cfg_set_u32(cfg, "rc:drop_gap", 1);         /* Do not continuous drop frame */

    /* setup bitrate for different rc_mode */
    mpp_enc_cfg_set_s32(cfg, "rc:bps_target", mppenc->bps);
    switch (mppenc->rc_mode) {
        case MPP_ENC_RC_MODE_FIXQP : {
            /* do not setup bitrate on FIXQP mode */
        } break;
        case MPP_ENC_RC_MODE_CBR : {
            /* CBR mode has narrow bound */
            mpp_enc_cfg_set_s32(cfg, "rc:bps_max", mppenc->bps_max ? mppenc->bps_max : mppenc->bps * 17 / 16);
            mpp_enc_cfg_set_s32(cfg, "rc:bps_min", mppenc->bps_min ? mppenc->bps_min : mppenc->bps * 15 / 16);
        } break;
        case MPP_ENC_RC_MODE_VBR :
        case MPP_ENC_RC_MODE_AVBR : {
            /* VBR mode has wide bound */
            mpp_enc_cfg_set_s32(cfg, "rc:bps_max", mppenc->bps_max ? mppenc->bps_max : mppenc->bps * 17 / 16);
            mpp_enc_cfg_set_s32(cfg, "rc:bps_min", mppenc->bps_min ? mppenc->bps_min : mppenc->bps * 1 / 16);
        } break;
        default : {
            /* default use CBR mode */
            mpp_enc_cfg_set_s32(cfg, "rc:bps_max", mppenc->bps_max ? mppenc->bps_max : mppenc->bps * 17 / 16);
            mpp_enc_cfg_set_s32(cfg, "rc:bps_min", mppenc->bps_min ? mppenc->bps_min : mppenc->bps * 15 / 16);
        } break;
    }

    /* setup qp for different codec and rc_mode */
    switch (mppenc->type) {
        case MPP_VIDEO_CodingAVC :
        case MPP_VIDEO_CodingHEVC : {
            switch (mppenc->rc_mode) {
            case MPP_ENC_RC_MODE_FIXQP : {
                RK_S32 fix_qp = mppenc->qp_init;

                mpp_enc_cfg_set_s32(cfg, "rc:qp_init", fix_qp);
                mpp_enc_cfg_set_s32(cfg, "rc:qp_max", fix_qp);
                mpp_enc_cfg_set_s32(cfg, "rc:qp_min", fix_qp);
                mpp_enc_cfg_set_s32(cfg, "rc:qp_max_i", fix_qp);
                mpp_enc_cfg_set_s32(cfg, "rc:qp_min_i", fix_qp);
                mpp_enc_cfg_set_s32(cfg, "rc:qp_ip", 0);
            } break;
            case MPP_ENC_RC_MODE_CBR :
            case MPP_ENC_RC_MODE_VBR :
            case MPP_ENC_RC_MODE_AVBR : {
                mpp_enc_cfg_set_s32(cfg, "rc:qp_init", -1);
                mpp_enc_cfg_set_s32(cfg, "rc:qp_max",  51);
                mpp_enc_cfg_set_s32(cfg, "rc:qp_min", 10);
                mpp_enc_cfg_set_s32(cfg, "rc:qp_max_i", 51);
                mpp_enc_cfg_set_s32(cfg, "rc:qp_min_i", 10);
                mpp_enc_cfg_set_s32(cfg, "rc:qp_ip", 2);
                /*
                mpp_enc_cfg_set_s32(cfg, "rc:qp_init", mppenc->qp_init ? mppenc->qp_init : -1);
                mpp_enc_cfg_set_s32(cfg, "rc:qp_max", mppenc->qp_max ? mppenc->qp_max : 51);
                mpp_enc_cfg_set_s32(cfg, "rc:qp_min", mppenc->qp_min ? mppenc->qp_min : 10);
                mpp_enc_cfg_set_s32(cfg, "rc:qp_max_i", mppenc->qp_max_i ? mppenc->qp_max_i : 51);
                mpp_enc_cfg_set_s32(cfg, "rc:qp_min_i", mppenc->qp_min_i ? mppenc->qp_min_i : 10);
                mpp_enc_cfg_set_s32(cfg, "rc:qp_ip", 2);
                */
            } break;
            default : {
                mpp_err_f("unsupport encoder rc mode %d\n", mppenc->rc_mode);
            } break;
            }
        } break;
        case MPP_VIDEO_CodingVP8 : {
            /* vp8 only setup base qp range */
            mpp_enc_cfg_set_s32(cfg, "rc:qp_init", mppenc->qp_init ? mppenc->qp_init : 40);
            mpp_enc_cfg_set_s32(cfg, "rc:qp_max",  mppenc->qp_max ? mppenc->qp_max : 127);
            mpp_enc_cfg_set_s32(cfg, "rc:qp_min",  mppenc->qp_min ? mppenc->qp_min : 0);
            mpp_enc_cfg_set_s32(cfg, "rc:qp_max_i", mppenc->qp_max_i ? mppenc->qp_max_i : 127);
            mpp_enc_cfg_set_s32(cfg, "rc:qp_min_i", mppenc->qp_min_i ? mppenc->qp_min_i : 0);
            mpp_enc_cfg_set_s32(cfg, "rc:qp_ip", 6);
        } break;
        case MPP_VIDEO_CodingMJPEG : {
            /* jpeg use special codec config to control qtable */
            mpp_enc_cfg_set_s32(cfg, "jpeg:q_factor", 80);
            mpp_enc_cfg_set_s32(cfg, "jpeg:qf_max", 99);
            mpp_enc_cfg_set_s32(cfg, "jpeg:qf_min", 1);
            /*
            mpp_enc_cfg_set_s32(cfg, "jpeg:q_factor", mppenc->qp_init ? mppenc->qp_init : 80);
            mpp_enc_cfg_set_s32(cfg, "jpeg:qf_max", mppenc->qp_max ? mppenc->qp_max : 99);
            mpp_enc_cfg_set_s32(cfg, "jpeg:qf_min", mppenc->qp_min ? mppenc->qp_min : 1);
            */
        } break;
        default : {
        } break;
    }

    /* setup codec  */
    mpp_enc_cfg_set_s32(cfg, "codec:type", mppenc->type);
    switch (mppenc->type) {
        case MPP_VIDEO_CodingAVC : {
            RK_U32 constraint_set;
            /*
            * H.264 profile_idc parameter
            * 66  - Baseline profile
            * 77  - Main profile
            * 100 - High profile
            */
            mpp_enc_cfg_set_s32(cfg, "h264:profile", 100);
            /*
            * H.264 level_idc parameter
            * 10 / 11 / 12 / 13    - qcif@15fps / cif@7.5fps / cif@15fps / cif@30fps
            * 20 / 21 / 22         - cif@30fps / half-D1@@25fps / D1@12.5fps
            * 30 / 31 / 32         - D1@25fps / 720p@30fps / 720p@60fps
            * 40 / 41 / 42         - 1080p@30fps / 1080p@30fps / 1080p@60fps
            * 50 / 51 / 52         - 4K@30fps
            */
            mpp_enc_cfg_set_s32(cfg, "h264:level", 40);
            mpp_enc_cfg_set_s32(cfg, "h264:cabac_en", 1);
            mpp_enc_cfg_set_s32(cfg, "h264:cabac_idc", 0);
            mpp_enc_cfg_set_s32(cfg, "h264:trans8x8", 1);

            mpp_env_get_u32("constraint_set", &constraint_set, 0);
            if (constraint_set & 0x3f0000)
                mpp_enc_cfg_set_s32(cfg, "h264:constraint_set", constraint_set);

        } break;
        case MPP_VIDEO_CodingHEVC :
        case MPP_VIDEO_CodingMJPEG :
        case MPP_VIDEO_CodingVP8 : {
        } break;
        default : {
            mpp_err_f("unsupport encoder coding type %d\n", mppenc->type);
        } break;
    }
     mppenc->split_mode = 0;
     mppenc->split_arg = 0;
     mppenc->split_out = 0;
 
     mpp_env_get_u32("split_mode", &mppenc->split_mode, MPP_ENC_SPLIT_NONE);
     mpp_env_get_u32("split_arg", &mppenc->split_arg, 0);
     mpp_env_get_u32("split_out", &mppenc->split_out, 0);
 
     if (mppenc->split_mode) {
        //  printf("%d split mode %d arg %d out %d\n",mppenc->split_mode, mppenc->split_arg, mppenc->split_out);
         mpp_enc_cfg_set_s32(cfg, "split:mode", mppenc->split_mode);
         mpp_enc_cfg_set_s32(cfg, "split:arg", mppenc->split_arg);
         mpp_enc_cfg_set_s32(cfg, "split:out", mppenc->split_out);
     }
 
     mpp_env_get_u32("mirroring", &mirroring, 0);
     mpp_env_get_u32("rotation", &rotation, 0);
     mpp_env_get_u32("flip", &flip, 0);
 
     mpp_enc_cfg_set_s32(cfg, "prep:mirroring", mirroring);
     mpp_enc_cfg_set_s32(cfg, "prep:rotation", rotation);
     mpp_enc_cfg_set_s32(cfg, "prep:flip", flip);
    // config gop_len and ref cfg
    mpp_enc_cfg_set_s32(cfg, "rc:gop", mppenc->fps_out_num * 2);

    
    ret = mppenc->mpi->control(mppenc->ctx, MPP_ENC_SET_CFG, cfg);
    if (ret) {
        mpp_err("mpi control enc cfg failed ret %d\n", ret);
        goto RET;
    }
    /* other optional set*/
    if (mppenc->type == MPP_VIDEO_CodingAVC || mppenc->type == MPP_VIDEO_CodingHEVC) {
        mppenc->header_mode = MPP_ENC_HEADER_MODE_EACH_IDR;
        ret =  mppenc->mpi->control(mppenc->ctx, MPP_ENC_SET_HEADER_MODE, &mppenc->header_mode);
        if (ret) {
            mpp_err("mpi control enc set header mode failed ret %d\n", ret);
            goto RET;
        }
    }
    
RET:
    return ret;
}

MPP_RET mpp_run(MPP_Encoder* mppenc,Uart_t* uart, RK_S32* out_cam_frm_idx)
{
    MppApi *mpi = mppenc->mpi;
    MppCtx ctx  = mppenc->ctx;
    MPP_RET ret = MPP_OK;
    
    int cnt = 0; //编码发送的第几帧
    uint8_t frame_id = 0; //编码发送的第几帧
#if 1
    //将假数据写到文件中
       // 添加文件指针（静态变量，确保只打开一次）
    static FILE *fake_file = NULL;
#else

#endif

    MppFrame frame = NULL;
    MppPacket packet = NULL;
    void *buf = NULL;
    RK_S32 cam_frm_idx = -1;  // 当前帧索引（函数内部）
    MppBuffer origin_buf = NULL;
    MppBuffer enc_buf = NULL;
    RK_U32 eoi = 1;

        // 初始化传出参数（确保外部能感知内部状态）
    if (out_cam_frm_idx)
        *out_cam_frm_idx = -1;
    
    do
    {
        // printf("ttyUSB0的文件句柄：%d\n",uart->fd);
        // 重置帧和包指针
        frame = NULL;
        packet = NULL;
        origin_buf = NULL;
        enc_buf = NULL;
        cam_frm_idx = -1;

        buf = mpp_buffer_get_ptr(mppenc->frm_buf);
        if (!buf && mppenc->usbcam_ctx == NULL) {
            mpp_err("无效的输入缓冲区\n");
            ret = MPP_ERR_NULL_PTR;
            break;
        }

        /* 区分不同设备的帧处理逻辑 */
        if (mppenc->usingnum == 0) {
            /* 红外摄像头：Grey转NV12 */
            if (mppenc->usbcam_ctx) {
                // 获取摄像头帧（检查有效性）
                cam_frm_idx = camera_source_get_frame(mppenc->usbcam_ctx);
                if (cam_frm_idx < 0) {
                    mpp_err("获取摄像头帧失败\n");
                    ret = MPP_ERR_TIMEOUT;
                    break;
                }
                // 同步传出当前帧索引（供线程退出时释放）
                if (out_cam_frm_idx)
                    *out_cam_frm_idx = cam_frm_idx;

                origin_buf = camera_frame_to_buf(mppenc->usbcam_ctx, cam_frm_idx);
                if (!origin_buf) {
                    mpp_err("获取帧缓冲区失败\n");
                    ret = MPP_ERR_NULL_PTR;
                    break;
                }
            } else {
                // 模拟帧填充（调试用）
                mpp_buffer_sync_begin(mppenc->frm_buf);
                fill_image((RK_U8 *)buf, mppenc->width, mppenc->height, 
                        mppenc->hor_stride, mppenc->ver_stride, 
                        mppenc->usbfmt, mppenc->frame_count);
                mpp_buffer_sync_end(mppenc->frm_buf);
                origin_buf = mppenc->frm_buf; // 使用模拟缓冲区
            }
            // 转码：Grey → NV12（检查缓冲区有效性）
            void* origin_data = mpp_buffer_get_ptr(origin_buf);
            void* enc_data = mpp_buffer_get_ptr(mppenc->enc_buf);
            if (!origin_data || !enc_data) {
                mpp_err("转码缓冲区为空\n");
                ret = MPP_ERR_NULL_PTR;
                break;
            }

            grey_to_nv12((unsigned char*)origin_data, (unsigned char*)enc_data,
                         mppenc->vwidth + 128, mppenc->vheight,
                         mppenc->width, mppenc->height);

            // 初始化编码帧
            ret = mpp_frame_init(&frame);
            if (ret) {
                mpp_err("初始化编码帧失败\n");
                break;
            }
            mpp_frame_set_width(frame, mppenc->width);
            mpp_frame_set_height(frame, mppenc->height);
            mpp_frame_set_hor_stride(frame, mppenc->hor_stride);
            mpp_frame_set_ver_stride(frame, mppenc->ver_stride);
            mpp_frame_set_fmt(frame, mppenc->usbfmt);
            mpp_frame_set_buffer(frame, mppenc->enc_buf);

        } else {
            /* 普通摄像头：直接使用原始帧 */
            if (mppenc->usbcam_ctx) {
                cam_frm_idx = camera_source_get_frame(mppenc->usbcam_ctx);
                if (cam_frm_idx < 0) {
                    mpp_err("获取摄像头帧失败\n");
                    ret = MPP_ERR_TIMEOUT;
                    break;
                }
                if (out_cam_frm_idx)
                    *out_cam_frm_idx = cam_frm_idx;

                enc_buf = camera_frame_to_buf(mppenc->usbcam_ctx, cam_frm_idx);
                if (!enc_buf) {
                    mpp_err("获取编码缓冲区失败\n");
                    ret = MPP_ERR_NULL_PTR;
                    break;
                }
            } else {
                // 模拟帧填充（调试用）
                mpp_buffer_sync_begin(mppenc->frm_buf);
                fill_image((RK_U8 *)buf, mppenc->width, mppenc->height,
                           mppenc->hor_stride, mppenc->ver_stride,
                           mppenc->usbfmt, mppenc->frame_count);
                mpp_buffer_sync_end(mppenc->frm_buf);
                enc_buf = mppenc->frm_buf;
            }

            // 初始化编码帧
            ret = mpp_frame_init(&frame);
            if (ret) {
                mpp_err("初始化编码帧失败\n");
                break;
            }
            mpp_frame_set_width(frame, mppenc->width);
            mpp_frame_set_height(frame, mppenc->height);
            mpp_frame_set_hor_stride(frame, mppenc->hor_stride);
            mpp_frame_set_ver_stride(frame, mppenc->ver_stride);
            mpp_frame_set_fmt(frame, mppenc->usbfmt);
            mpp_frame_set_buffer(frame, enc_buf);
        }
        /* 编码处理 */
        // 初始化输出包
        ret = mpp_packet_init_with_buffer(&packet, mppenc->pkt_buf);
        if (ret) {
            mpp_err("初始化输出包失败\n");
            break;
        }
        mpp_packet_set_length(packet, 0); // 重置长度

        // 发送帧到编码器
        ret = mpi->encode_put_frame(ctx, frame);
        if (ret) {
            mpp_err("发送帧到编码器失败\n");
            break;
        }

        // 获取编码结果
        ret = mpi->encode_get_packet(ctx, &packet);
        if (ret) {
            mpp_err("获取编码包失败\n");
            break;
        }
        // 处理编码结果（写入文件+串口发送）
        if (packet) {
            void *ptr = mpp_packet_get_pos(packet);
            size_t len = mpp_packet_get_length(packet);
            mppenc->pkt_eos = mpp_packet_get_eos(packet);

            // 写入文件
            if (mppenc->fp_output && ptr && len > 0) {
                // fwrite(ptr, len, 1, mppenc->fp_output);
                // fflush(mppenc->fp_output);
            }
#if 1
            // 串口发送（带重试逻辑）
            if (len > 0 && uart->fd > 0) {
                int uart_ret = -1;

                pthread_mutex_lock(&usb0_data_lock);
                uart_ret = uart_send_h265_frame(uart->fd, ptr, len);
                pthread_mutex_unlock(&usb0_data_lock);
                if (uart_ret != 0){
                    perror("数据未发送，即将发送单原子性的下一帧");
                    break;
                }
                        
            }
#else 
                // 替换原有的H.265帧发送逻辑
            if (len > 0 && uart->fd > 0 ) {
                int uart_ret = -1;
                
                // 帧结构总大小 =数据(20000)
                size_t frame_size = 20000;
                uint8_t *frame_buffer = (uint8_t *)malloc(frame_size);
                if (!frame_buffer) {
                    perror("内存分配失败");
                    break;
                }
                
                // 4. 生成假数据：从0x01到0xFF循环的字节流
                static uint8_t fake_byte_value = 0x01;  // 静态变量，初始值为0x01
                for (int i = 0; i < 20000; i++) {
                    frame_buffer[i] = fake_byte_value;
                    
                    // 递增数值，达到0xFF后重置为0x01
                    fake_byte_value = (fake_byte_value == 0xFF) ? 0x01 : fake_byte_value + 1;  // 循环递增
                }

                
                // 打印调试信息
                printf("##发送假数据:[");
                fflush(stdout);
                // 打印完整的帧信息（修复后的代码）
                printf("帧: 0x%02X 0x%02X  0x%02X 0x%02X 0x%02X  ]\n", 
                    frame_buffer[0], frame_buffer[1], 
                    frame_buffer[2], frame_buffer[3], 
                    frame_buffer[4]);
                fflush(stdout);

                
                // 加锁并通过串口发送数据
                pthread_mutex_lock(&usb0_data_lock);
                uart_ret = uart_send_h265_frame(uart->fd, frame_buffer, frame_size);
                pthread_mutex_unlock(&usb0_data_lock);
                
                free(frame_buffer); // 释放临时缓冲区
                
                if (uart_ret != 0) {
                    perror("数据发送失败");
                    break;
                }
            }
#endif
            // 更新统计信息
            mppenc->stream_size += len;
            mppenc->frame_count += eoi;
            frame_id = (frame_id >= 1000) ? 1 : frame_id + 1;
            cnt++;

            mpp_packet_deinit(&packet); // 释放包
        }

        // 标记帧处理完成
        mppenc->frame_count++;
        //编码，一帧结束
        // printf("##[%d frame_id] ##-----> [",frame_id);
        // printf("encoder 当前第 %d frame ]\n",cnt);

    } while (0); // 仅执行一次（单帧原子性处理）
    /* 资源清理（确保所有路径都释放资源） */
    // 归还摄像头帧
    if (cam_frm_idx >= 0 && mppenc->usbcam_ctx) {
        camera_source_put_frame(mppenc->usbcam_ctx, cam_frm_idx);
        if (out_cam_frm_idx)
            *out_cam_frm_idx = -1; // 标记已归还
    }

    // 释放帧和包
    if (frame) {
        mpp_frame_deinit(&frame);
    }
    if (packet) {
        mpp_packet_deinit(&packet);
    }
#if 1
        // 程序退出前关闭文件（如果打开过）
    if (ret != MPP_OK && fake_file != NULL) {
        fclose(fake_file);
        fake_file = NULL;
        printf("已关闭fake_data.bin\n");
    }
#endif
    // 处理异常退出时的状态重置
    if (ret != MPP_OK) {
        mppenc->pkt_eos = 1; // 触发退出逻辑
    }

    return ret;
    
}
void mpp_params_show(MPP_Encoder *mppenc)
{
    printf("width %d \n", mppenc->width);
    printf("height %d \n", mppenc->height);
    printf("usbfmt %d \n", mppenc->usbfmt);
    printf("type %d \n", mppenc->type);
    printf("rc_mode %d \n", mppenc->rc_mode);
    printf("hor_stride %d \n", mppenc->hor_stride);
    printf("ver_stride %d \n", mppenc->ver_stride);

}
/*
 只需要对video设备号进行采集和编码，最后将数据通过单线程写入到串口ttyUSB0
*/
void* encoder_thd1_vis(void* arg)
{
    printf("------encoder_thd1_vis-----\n");
    MPP_RET ret = MPP_OK;
    bool init_success = false;
    int single = 0;  // 将声明移到goto可能到达的范围之外
//new:更新参数

   // 使用传递的参数初始化编码器 相关参数
    MPP_Encoder* enc_ctx = Mpp_encoder_init(
        640,      // 使用传递的宽度
        480,     // 使用传递的高度
        15,        // 使用传递的帧率
        20,     // 使用传递的设备号
        MPP_FMT_YUV422_YUYV
    );
    printf("-----test----\n");
//new:
//1 初始化参数
    // MPP_Encoder* enc_ctx = (MPP_Encoder *)malloc(sizeof(MPP_Encoder));
    // memset(enc_ctx, 0 , sizeof(MPP_Encoder)); 
    // enc_ctx = Mpp_encoder_init(640, 480, 30, 0, MPP_FMT_YUV420SP);

//2 初始化缓冲区
    ret = mpp_buffer_group_get_internal(&enc_ctx->buf_grp, MPP_BUFFER_TYPE_DRM);
    if (ret) {
        perror("failed to get mpp buffer group ret \n");
        goto MPP_OUT;
    }
    ret = mpp_buffer_get(enc_ctx->buf_grp, &enc_ctx->frm_buf, enc_ctx->frame_size + enc_ctx->header_size);
    if (ret) {
        perror("failed to get buffer for input frame ret \n");
        goto MPP_OUT;
    }
    ret = mpp_buffer_get(enc_ctx->buf_grp, &enc_ctx->pkt_buf, enc_ctx->frame_size);
    if (ret) {
        perror("failed to get buffer for output packet ret \n");
        goto MPP_OUT;
    }
    ret = mpp_buffer_get(enc_ctx->buf_grp, &enc_ctx->md_info, enc_ctx->mdinfo_size);
    if (ret) {
        perror("failed to get buffer for motion info output packet ret \n");
        goto MPP_OUT;
    }
    //分配转码所用的buffer video20
    ret = mpp_buffer_get(enc_ctx->buf_grp, &enc_ctx->enc_buf, enc_ctx->frame_size + enc_ctx->header_size);
    
printf("enthd:frame_size = [%ld],header_size = [%ld]\n",enc_ctx->frame_size , enc_ctx->header_size);
    if (ret) {
        perror("failed to get buffer for input frame ret \n");
        goto MPP_OUT;
    }
//3 初始化mpp
    ret = mpp_create(&enc_ctx->ctx, &enc_ctx->mpi);
    if (ret) {
        mpp_err("mpp_create failed ret %d\n", ret);
        goto MPP_OUT;
    }
printf("%p encoder test start w %d h %d type %d\n", enc_ctx->ctx, enc_ctx->width, enc_ctx->height, enc_ctx->type);
    ret = enc_ctx->mpi->control(enc_ctx->ctx, MPP_SET_OUTPUT_TIMEOUT, &enc_ctx->timeout);
    if (MPP_OK != ret) {
        mpp_err("mpi control set output timeout %d ret %d\n", enc_ctx->timeout, ret);
        goto MPP_OUT;
    }
    ret = mpp_init(enc_ctx->ctx, MPP_CTX_ENC, enc_ctx->type);
    if (ret) {
        mpp_err("mpp_init failed ret %d\n", ret);
        goto MPP_OUT;
    }

    ret = mpp_enc_cfg_init(&enc_ctx->cfg);
    if (ret) {
        mpp_err_f("mpp_enc_cfg_init failed ret %d\n", ret);
        goto MPP_OUT;
    }

    ret = enc_ctx->mpi->control(enc_ctx->ctx, MPP_ENC_GET_CFG, enc_ctx->cfg);
    if (ret) {
        mpp_err_f("get enc cfg failed ret %d\n", ret);
        goto MPP_OUT;
    }

    ret = mpp_enc_cfg_setup(enc_ctx);
    if (ret) {
        mpp_err_f("test mpp setup failed ret %d\n", ret);
        goto MPP_OUT;
    }
    //输出调试信息
    mpp_params_show(enc_ctx);

        // 标记初始化成功
    init_success = true;

#if 1
    // 多次编码
    while(!thread1_should_exit)
    {
        // ret = mpp_run(enc_ctx, NULL, &enc_ctx->cam_frm_idx);
        ret = mpp_run(enc_ctx, g_uart_usb0, &enc_ctx->cam_frm_idx);
        if (ret) {
            mpp_err_f("test mpp run failed ret %d\n", ret);
            goto MPP_OUT;
        }

        ret = enc_ctx->mpi->reset(enc_ctx->ctx);
        if (ret) {
            mpp_err("mpi->reset failed\n");
            goto MPP_OUT;
        }
    }

#else
        // 单次编码（使用do-while确保至少执行一次）
        do {
            if (!thread1_should_exit) {
                ret = mpp_run(enc_ctx, g_uart_usb0, &enc_ctx->cam_frm_idx);
                if (ret) {
                    mpp_err_f("test mpp run failed ret %d\n", ret);
                    goto MPP_OUT;  // 现在不会跳过single的初始化
                } else {
                    printf("Single encode operation completed successfully.\n");
                }
                single++;
            } else {
                break;
            }
        } while (single < 1);  // 正确：single已被初始化

#endif

MPP_OUT:
    // 退出前强制释放未归还的摄像头帧缓冲区
    if (enc_ctx->cam_frm_idx >= 0 && enc_ctx->usbcam_ctx) {
        camera_source_put_frame(enc_ctx->usbcam_ctx, enc_ctx->cam_frm_idx);
        enc_ctx->cam_frm_idx = -1; // 标记已释放
    }
    if (init_success) {

        if (enc_ctx->ctx) {
            mpp_destroy(enc_ctx->ctx);
            enc_ctx->ctx = NULL;
        }

        if (enc_ctx->cfg) {
            mpp_enc_cfg_deinit(enc_ctx->cfg);
            enc_ctx->cfg = NULL;
        }

        if (enc_ctx->enc_buf) {
            mpp_buffer_put(enc_ctx->enc_buf);
            enc_ctx->enc_buf = NULL;
        }

        if (enc_ctx->frm_buf) {
            mpp_buffer_put(enc_ctx->frm_buf);
            enc_ctx->frm_buf = NULL;
        }

        if (enc_ctx->pkt_buf) {
            mpp_buffer_put(enc_ctx->pkt_buf);
            enc_ctx->pkt_buf = NULL;
        }

        if (enc_ctx->md_info) {
            mpp_buffer_put(enc_ctx->md_info);
            enc_ctx->md_info = NULL;
        }

        if (enc_ctx->buf_grp) {
            mpp_buffer_group_put(enc_ctx->buf_grp);
            enc_ctx->buf_grp = NULL;
        }

    }
    if (enc_ctx->usbcam_ctx) {
        camera_source_deinit(enc_ctx->usbcam_ctx);
        enc_ctx->usbcam_ctx = NULL;
    }
    if (enc_ctx) {
        Mpp_encoder_deinit(enc_ctx); // 最终释放enc_ctx
    }
    return NULL;
}


void* encoder_thd2_icr(void* arg)
{
    printf("------encoder_thd2-----\n");
    MPP_RET ret = MPP_OK;
    bool init_success = false;
//new:更新参数
//new:
//1 初始化参数

    MPP_Encoder* enc_ctx = Mpp_encoder_init(640, 480, 30, 0, MPP_FMT_YUV420SP);

//2 初始化缓冲区
    ret = mpp_buffer_group_get_internal(&enc_ctx->buf_grp, MPP_BUFFER_TYPE_DRM);
    if (ret) {
        perror("failed to get mpp buffer group ret \n");
        goto MPP_OUT;
    }
    ret = mpp_buffer_get(enc_ctx->buf_grp, &enc_ctx->frm_buf, enc_ctx->frame_size + enc_ctx->header_size);
    if (ret) {
        perror("failed to get buffer for input frame ret \n");
        goto MPP_OUT;
    }
    ret = mpp_buffer_get(enc_ctx->buf_grp, &enc_ctx->pkt_buf, enc_ctx->frame_size);
    if (ret) {
        perror("failed to get buffer for output packet ret \n");
        goto MPP_OUT;
    }
    ret = mpp_buffer_get(enc_ctx->buf_grp, &enc_ctx->md_info, enc_ctx->mdinfo_size);
    if (ret) {
        perror("failed to get buffer for motion info output packet ret \n");
        goto MPP_OUT;
    }
    //分配转码所用的buffer video0
    ret = mpp_buffer_get(enc_ctx->buf_grp, &enc_ctx->enc_buf, 
                    (enc_ctx->usingnum == 0) ? 640*480*3/2 : enc_ctx->frame_size);
    printf("enthd:frame_size = [%ld],header_size = [%ld]\n",enc_ctx->frame_size , enc_ctx->header_size);
    if (ret) {
        perror("failed to get buffer for input frame ret \n");
        goto MPP_OUT;
    }
//3 初始化mpp
    ret = mpp_create(&enc_ctx->ctx, &enc_ctx->mpi);
    if (ret) {
        mpp_err("mpp_create failed ret %d\n", ret);
        goto MPP_OUT;
    }
    printf("%p encoder test start w %d h %d type %d\n", enc_ctx->ctx, enc_ctx->width, enc_ctx->height, enc_ctx->type);
    ret = enc_ctx->mpi->control(enc_ctx->ctx, MPP_SET_OUTPUT_TIMEOUT, &enc_ctx->timeout);
    if (MPP_OK != ret) {
        mpp_err("mpi control set output timeout %d ret %d\n", enc_ctx->timeout, ret);
        goto MPP_OUT;
    }
    ret = mpp_init(enc_ctx->ctx, MPP_CTX_ENC, enc_ctx->type);
    if (ret) {
        mpp_err("mpp_init failed ret %d\n", ret);
        goto MPP_OUT;
    }

    ret = mpp_enc_cfg_init(&enc_ctx->cfg);
    if (ret) {
        mpp_err_f("mpp_enc_cfg_init failed ret %d\n", ret);
        goto MPP_OUT;
    }

    ret = enc_ctx->mpi->control(enc_ctx->ctx, MPP_ENC_GET_CFG, enc_ctx->cfg);
    if (ret) {
        mpp_err_f("get enc cfg failed ret %d\n", ret);
        goto MPP_OUT;
    }

    ret = mpp_enc_cfg_setup(enc_ctx);
    if (ret) {
        mpp_err_f("test mpp setup failed ret %d\n", ret);
        goto MPP_OUT;
    }
    //输出调试信息
    mpp_params_show(enc_ctx);
    init_success = true;
    while(!thread2_should_exit)
    {
        if (thread2_write_data_to_uart == 1)
        {
            ret = mpp_run(enc_ctx, g_uart_usb0, &enc_ctx->cam_frm_idx);
            if (ret) {
                mpp_err_f("test mpp run failed ret %d\n", ret);
                goto MPP_OUT;
            }

            ret = enc_ctx->mpi->reset(enc_ctx->ctx);
            if (ret) {
                mpp_err("mpi->reset failed\n");
                goto MPP_OUT;
            }
        }

    }
    

MPP_OUT:
    // 退出前强制释放未归还的摄像头帧缓冲区
    if (enc_ctx->cam_frm_idx >= 0 && enc_ctx && enc_ctx->usbcam_ctx) {
        camera_source_put_frame(enc_ctx->usbcam_ctx, enc_ctx->cam_frm_idx);
        enc_ctx->cam_frm_idx = -1; // 标记已释放
    }
    if (init_success) {

        if (enc_ctx->ctx) {
            mpp_destroy(enc_ctx->ctx);
            enc_ctx->ctx = NULL;
        }

        if (enc_ctx->cfg) {
            mpp_enc_cfg_deinit(enc_ctx->cfg);
            enc_ctx->cfg = NULL;
        }

        if (enc_ctx->enc_buf) {
            mpp_buffer_put(enc_ctx->enc_buf);
            enc_ctx->enc_buf = NULL;
        }

        if (enc_ctx->frm_buf) {
            mpp_buffer_put(enc_ctx->frm_buf);
            enc_ctx->frm_buf = NULL;
        }

        if (enc_ctx->pkt_buf) {
            mpp_buffer_put(enc_ctx->pkt_buf);
            enc_ctx->pkt_buf = NULL;
        }

        if (enc_ctx->md_info) {
            mpp_buffer_put(enc_ctx->md_info);
            enc_ctx->md_info = NULL;
        }

        if (enc_ctx->buf_grp) {
            mpp_buffer_group_put(enc_ctx->buf_grp);
            enc_ctx->buf_grp = NULL;
        }
        if (enc_ctx->usbcam_ctx) {
            camera_source_deinit(enc_ctx->usbcam_ctx);
            enc_ctx->usbcam_ctx = NULL;
        }
        Mpp_encoder_deinit(enc_ctx);
    }
    if (enc_ctx) { // 即使init_success为false，也需检查并释放已分配的资源
        if (enc_ctx->usbcam_ctx) {
            camera_source_deinit(enc_ctx->usbcam_ctx);
            enc_ctx->usbcam_ctx = NULL;
        }
        Mpp_encoder_deinit(enc_ctx); // 最终释放enc_ctx
    }
    return NULL;
}


